/**
 * Copyright (c) iwindplus Technologies Co., Ltd.2024-2030, All rights reserved.
 */

package com.iwindplus.im.server.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.google.common.collect.Lists;
import com.iwindplus.boot.domain.constant.CommonConstant.UserConstant;
import com.iwindplus.boot.domain.enums.BizCodeEnum;
import com.iwindplus.boot.domain.exception.BizException;
import com.iwindplus.boot.domain.vo.FilePathVO;
import com.iwindplus.boot.domain.vo.ResultVO;
import com.iwindplus.boot.mongo.service.impl.MongoBaseServiceImpl;
import com.iwindplus.im.domain.dto.GroupChatMsgDTO;
import com.iwindplus.im.domain.dto.GroupChatMsgSearchDTO;
import com.iwindplus.im.domain.enums.ImCodeEnum;
import com.iwindplus.im.domain.enums.SendStatusEnum;
import com.iwindplus.im.domain.vo.GroupChatMsgPageVO;
import com.iwindplus.im.domain.vo.GroupChatMsgVO;
import com.iwindplus.im.server.model.ChatGroupDO;
import com.iwindplus.im.server.model.GroupChatMsgDO;
import com.iwindplus.im.server.service.ChatGroupService;
import com.iwindplus.im.server.service.GroupChatMsgService;
import com.iwindplus.mgt.client.power.UserClient;
import com.iwindplus.mgt.domain.vo.power.UserExtendVO;
import com.iwindplus.setup.client.OssClient;
import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 群聊消息业务层接口实现类.
 *
 * @author zengdegui
 * @since 2020/3/25
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class GroupChatMsgServiceImpl extends MongoBaseServiceImpl<GroupChatMsgDO> implements GroupChatMsgService {
    @Lazy
    @Resource
    private ChatGroupService chatGroupService;

    @Resource
    private OssClient ossClient;

    @Resource
    private UserClient userClient;

    @Override
    public boolean save(GroupChatMsgDTO entity) {
        Long userId = entity.getSenderId();
        Long orgId = entity.getOrgId();

        List<Long> ids = Arrays.asList(userId);
        final UserExtendVO data = Optional.ofNullable(this.userClient.listExtendByIds(ids)).map(ResultVO::getBizData).map(m -> m.get(0)).orElse(null);
        if (Objects.isNull(data)) {
            throw new BizException(BizCodeEnum.DATA_NOT_EXIST);
        }
        String avatar = data.getAvatar();
        String nickName = data.getNickName();
        final ChatGroupDO result = this.chatGroupService.getById(entity.getChatGroupId());
        if (Objects.isNull(result)) {
            throw new BizException(ImCodeEnum.CHAT_GROUP_NOT_EXIST);
        }
        entity.setSeq(this.getNextSeq(orgId, entity.getChatGroupId()));
        entity.setSenderId(userId);
        entity.setSenderAvatar(avatar);
        entity.setSenderNickName(nickName);
        entity.setOrgId(orgId);
        final GroupChatMsgDO model = BeanUtil.copyProperties(entity, GroupChatMsgDO.class);
        super.save(model);
        entity.setId(model.getId());
        return Boolean.TRUE;
    }

    @Override
    public boolean edit(GroupChatMsgDTO entity) {
        GroupChatMsgDO data = super.getById(entity.getId());
        if (Objects.isNull(data)) {
            throw new BizException(BizCodeEnum.DATA_NOT_EXIST);
        }
        final GroupChatMsgDO model = BeanUtil.copyProperties(entity, GroupChatMsgDO.class);
        return super.updateById(model);
    }

    @Override
    public boolean removeByChatGroupIds(List<Long> chatGroupIds) {
        super.removeByIds(chatGroupIds, false);
        return Boolean.TRUE;
    }

    @Override
    public IPage<GroupChatMsgPageVO> page(PageDTO<GroupChatMsgDO> page, GroupChatMsgSearchDTO entity) {
        Long orgId = entity.getOrgId();
        Criteria criteria = Criteria.where(UserConstant.ORG_ID).is(orgId).and("chatGroupId").is(entity.getChatGroupId());
        if (Objects.nonNull(entity.getSenderId())) {
            criteria.and("senderId").is(entity.getSenderId());
        }
        if (Objects.isNull(entity.getSendStatus())) {
            entity.setSendStatus(SendStatusEnum.SUCCESS);
        }
        criteria.and("sendStatus").is(entity.getSendStatus());
        final Query query = Query.query(criteria);
        List<OrderItem> orders = page.getOrders();
        if (CollUtil.isEmpty(orders)) {
            orders = new ArrayList<>(10);
            OrderItem orderItem = OrderItem.desc("modifiedTime");
            orders.add(orderItem);
            page.setOrders(orders);
        }
        final IPage<GroupChatMsgDO> modelPage = super.page(page, query);
        final IPage<GroupChatMsgPageVO> result = modelPage.convert(model -> BeanUtil.copyProperties(model, GroupChatMsgPageVO.class));
        this.buildUserPic(result.getRecords(), entity.getMgtOssTplCode());
        return result;
    }

    @Override
    public GroupChatMsgVO getDetail(String id, String ossTplCode) {
        GroupChatMsgDO data = super.getById(id);
        if (Objects.isNull(data)) {
            throw new BizException(BizCodeEnum.DATA_NOT_EXIST);
        }
        List<String> relativePaths = Lists.newArrayList();
        if (CharSequenceUtil.isNotBlank(data.getSenderAvatar())) {
            relativePaths.add(data.getSenderAvatar());
        }
        List<FilePathVO> filePaths = DirectMsgServiceImpl.getFilePaths(ossTplCode, relativePaths, this.ossClient);
        final GroupChatMsgVO result = BeanUtil.copyProperties(data, GroupChatMsgVO.class);
        this.buildUserInfo(result, filePaths);
        return result;
    }

    /**
     * 查询下一个排序号.
     *
     * @param orgId       组织主键
     * @param chatGroupId 聊天群主键
     * @return Integer
     */
    private Integer getNextSeq(Long orgId, Long chatGroupId) {
        List<AggregationOperation> operations = new ArrayList<>(10);
        operations.add(Aggregation.match(Criteria.where(UserConstant.ORG_ID).is(orgId).and("chatGroupId").is(chatGroupId)));
        operations.add(Aggregation.group(UserConstant.ORG_ID, "chatGroupId").max("seq").as("seq"));
        Aggregation aggregation = Aggregation.newAggregation(operations);
        final AggregationResults<GroupChatMsgDO> result = this.getMongoTemplate().aggregate(aggregation, GroupChatMsgDO.class, GroupChatMsgDO.class);
        final GroupChatMsgDO data = result.getUniqueMappedResult();
        return Optional.ofNullable(data).map(x -> x.getSeq() + 1).orElse(1);
    }

    private void buildUserPic(List<GroupChatMsgPageVO> records, String ossTplCode) {
        if (CollUtil.isNotEmpty(records) && CharSequenceUtil.isNotBlank(ossTplCode)) {
            List<String> senderAvatars = records.stream().filter(m -> CharSequenceUtil.isNotBlank(m.getSenderAvatar()))
                    .map(GroupChatMsgPageVO::getSenderAvatar).distinct().collect(Collectors.toCollection(ArrayList::new));
            List<String> relativePaths = Lists.newArrayList();
            if (CollUtil.isNotEmpty(senderAvatars)) {
                relativePaths.addAll(senderAvatars);
            }
            List<FilePathVO> filePaths = DirectMsgServiceImpl.getFilePaths(ossTplCode, relativePaths, this.ossClient);
            records.forEach(m -> this.buildUserInfo(m, filePaths));
        }
    }

    private void buildUserInfo(GroupChatMsgPageVO data, List<FilePathVO> filePaths) {
        if (CollUtil.isEmpty(filePaths)) {
            return;
        }
        filePaths.forEach(p -> {
            if (CharSequenceUtil.isNotBlank(data.getSenderAvatar()) && data.getSenderAvatar().equals(p.getRelativePath())) {
                data.setSenderAvatar(p.getAbsolutePath());
            }
        });
    }

    private void buildUserInfo(GroupChatMsgVO data, List<FilePathVO> filePaths) {
        if (CollUtil.isEmpty(filePaths)) {
            return;
        }
        filePaths.forEach(p -> {
            if (CharSequenceUtil.isNotBlank(data.getSenderAvatar()) && data.getSenderAvatar().equals(p.getRelativePath())) {
                data.setSenderAvatar(p.getAbsolutePath());
            }
        });
    }
}
